Union

Unions with Parametric Polymorphism (Parapoly)

Error :: enum {Foo0, Foo1, Foo2}
Param_Union :: union($T: typeid) #no_nil {T, Error}
r: Param_Union(int)
r = 123
r = Error.Foo0

Union Casting

  • Limitations with Pointer Casting :

    • Caio:

      • how do I convert a 'pointer to a value', to a 'pointer to a union'? I'm doing cast(^My_Union)value , where value: ^$T , with T  being a generic parameter for a procedure, but I'm getting an "index out of bounds" error while trying to cast a [2]f32

    • Blob:

      • you can't, unions are <data><tag> . meaning they're bigger than their types. the tag is just an index into an array in the RTTI.

      • except for unions with only a single pointer type union{^T}  where the tag is dropped & the nil check just checks if the pointer is nil.

Print

  • Union type :

fmt.printfln("%T", my_union)
// or
fmt.printfln("%v", typeid_of(type_of(my_union)))
  • Unwrapped Union type :

fmt.printfln("%v", reflect.union_variant_typeid(my_union))

Type check

Via value.(T)
Value :: union {
    bool,
    i32,
    f32,
    string,
}
v: Value
v = "Hellope"

// type assert that `v` is a `string` and panic otherwise.
s1 := v.(string)

// type assert but with an explicit BOOLEAN check. This will not panic.
s2, ok := v.(string)
if !ok {
    // problem encountered.
}
Via Switch Statement
  • A type switch allows several type assertions in series.

  • A type switch is like a regular switch, but the cases are types (not values).

  • For a union, only the union's types are allowed as case types.

value: Value = ...
switch v in value {
case string:
    #assert(type_of(v) == string)

case bool:
    #assert(type_of(v) == bool)

case i32, f32:
    // This case allows multiple types, therefore we cannot know which type to use
    // `v` remains the original union value
    #assert(type_of(v) == Value)
case:
    // Default case
    // In this case, it is `nil`
}

Maybe

  • Maybe .

  • A union which either  returns a type T  or nil . In other languages, often seen as Option(T) , Result(T) , etc.

  • Not used much, as Odin supports multiple return values.

halve :: proc(n: int) -> Maybe(int) {
    if n % 2 != 0 do return nil
    return n / 2
}

half, ok := halve(2).?
if ok do fmt.println(half)       // 1
half, ok = halve(3).?
if !ok do fmt.println("3/2 isn't an int")

n := halve(4).? or_else 0
fmt.println(n)                   // 2